﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DC2010.Objects;
using DC2010.Objects.Data;
using DC2010.Objects.Structures;

namespace DC2010
{
    public partial class Calculations
    {

                //*********************************************************
                //
                //*********************************************************
                //  TAG01bf9a

        /// <summary>
        /// Attack
        /// </summary>
        /// <param name="AttackedParty">Attacked party object</param>
        /// <param name="initialChIdx">Old: id char to attack first</param>
        /// <param name="initialAttackType">Old: Attack type</param>
        /// <param name="Attacker">Attacker object</param>
        public void Attack(
                    CreatureData Attacker,
                    PartyData AttackedParty,
                    int initialChIdx, ActionInfo initialAttackType)
                {//(i16)
                  int D0L, D0W, D4L, D4W, D6L, D6W;
                  TileType rtD0;
                  //static RN   rnD5;
            
				//attacked creature
                  CreatureData pChar;
                  //static DBCOMMON *dbA2;
                  //static DB5      *DB5A2;
                  //static DB10     *DB10A2;
                  //static i32 attackX, attackY;
                  int   w_42;
                  //static TIMER timer_32;
//                  static WEAPONDESC  *pWeapon_22;
  //                static WEAPONDESC  *pWeapon_18;
                  //static i32 skillNumber; //w_12
                  // w_8 = attackY
                  // w_6 = attackX
                  //static i32 disableTime, staminaCost, experienceGained;
                  int range;
                  int successfulAttack;
                  //static RN  obj_4;
                  int wpnByte1_4;
                  int neededHP_4;
                  //static i32 neededMana;
                  ATTACKPARAMETERS pParam = new ATTACKPARAMETERS();
                  //static FILTER filter;
                  range = 0xccc;//Compiler says not initialized.
                //;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                  //D7W = sw(chIdx);
            
            //pick attacked creature
                  PartyData AttackersParty = Attacker.L.GetParty();
                    pChar = AttackedParty.GetCreatureByIndex(initialChIdx);
                  // Weapon hand = 1;
//                  dbA2 = GetCommonAddress(pChar->Possession(1));
  //                if (pChar->HP() == 0) RETURN_i16(0);

                  //pParam = SetupDSAParam(&filter);
                  pParam.charIdx = initialChIdx;
                  pParam.attackType = initialAttackType;
                  pParam.neededMana = 0;

            pParam.attackX = AttackersParty.Location.X;// d.partyX;
            pParam.attackY = AttackersParty.Location.Y;//  d.partyY;
//                  pParam.attackX += d.DeltaX[pChar->facing];
  //                pParam.attackY += d.DeltaY[pChar->facing];
                  //if (TimerTraceActive || AttackTraceActive)
                  //{
                  //  fprintf(GETFILE(TraceFile),"%s attacks from %02x(%02x,%02x)"
                  //                    " to %02x(%02x,%02x)\n",
                  //          d.CH16482[pParam->charIdx].name,
                  //          d.partyLevel,d.partyX,d.partyY,
                  //          d.partyLevel,pParam->attackX, pParam->attackY);
                  //};
                  //if (AttackTraceActive)
                  //{
                  //  i32 i;
                  //  i = pParam->attackType;
                  //  char *pAName;
                  //  for (pAName = (char *)d.AttackNames; i != 0; i--)
                  //  {
                  //    while ( *(pAName++) != 0) {}; // Skip one string
                  //  };

                  //  fprintf(GETFILE(TraceFile),"Attack type = %d = %s\n",
                  //                pParam->attackType, pAName);
                  //};
            
				// Find monster to attack
                  pChar = AttackedParty.L.FindFirstMonster(pParam.attackX, pParam.attackY);
                  pParam.monsterUnderAttack =  pChar.Id;
                  //if (pParam->monsterUnderAttack != RNeof)
                  //{
                  //  pParam->monsterType = GetRecordAddressDB4(d.MonsterUnderAttack)->monsterType();
                  //}
                  //else
                  //{
                  //  pParam.monsterUnderAttack = "";
                  //  //pParam->monsterType = mon_undefined;
                  //};
            pParam.disableTime = initialAttackType.Fatique; //0;//(UI8)(d.Byte19914[pParam->attackType]); // small integer (2,6,12)
            pParam.skillNumber = (int)initialAttackType.ImprovedSkill;
            pParam.staminaCost = initialAttackType.Stamina + STRandomBool();
            pParam.experienceGained = initialAttackType.ExperienceGain;
            //GetExperienceForAttacting(pParam.attackType);
            //Root.I.GameSystem. (d.experienceForAttacking[pParam->attackType]);
                        //small integers.  largest 35.

                  pParam.activateMonster = 0;
                  //D6W = GetCellFlags(pParam->attackX, pParam->attackY);
                  successfulAttack = 1;
                //
                  if (   (pParam.skillNumber == (int)SkillNames.SKILL_Fire /*16*/)  // All the Wizard skills
                      || (pParam.skillNumber == (int)SkillNames.SKILL_Air /*17*/)
                      || (pParam.skillNumber == (int)SkillNames.SKILL_Earth /*18*/)
                      || (pParam.skillNumber == (int)SkillNames.SKILL_Water /*19*/)
                      || (pParam.skillNumber ==  (int)SkillNames.SKILL_Wizard /*3*/) )
                  {
                    pParam.neededMana = (7-Smaller(6, DetermineMastery(Attacker, pParam.charIdx, pParam.skillNumber)));
                    //if (AttackTraceActive)
                    //{
                    //  fprintf(GETFILE(TraceFile),"Skill %d is Wizard skill.  Mastery=%d\n",
                    //        pParam->skillNumber, DetermineMastery(pParam->charIdx,pParam->skillNumber));
                    //  fprintf(GETFILE(TraceFile),"neededMana = 7-min(6,Mastery) = %d\n",pParam->neededMana);
                    //};
                  }
                  else
                  {
                    pParam.neededMana = 0;
                  }
                  //CallAttackFilter(&filter, pParam, 0);
                  //if (pParam.attackType < 0) return 0;
                  switch (pParam.attackType.Method)
                  {
                  case "LIGHTNING":  //PAF
                      range = 180;
                          SpellInfo siLighting = Root.I.SpellSystem.GetInfo("SPELL_LIGHTNING");
                      successfulAttack = AttackWithSpell(Attacker, AttackedParty, pParam, range, siLighting, pParam.neededMana, ref pParam.experienceGained);
                      pChar.Inventory.GetAttackingWeapon().L.DecrementChargesRemaining();
                      
                      
                      break;
                  case "DISPELL": //PAF
                      range = 150;
                          SpellInfo siDispell = Root.I.SpellSystem.GetInfo("SPELL_DISPELL");
                      successfulAttack = AttackWithSpell(Attacker, AttackedParty, pParam, range, siDispell, pParam.neededMana, ref pParam.experienceGained);
                      pChar.Inventory.GetAttackingWeapon().L.DecrementChargesRemaining();
                      break;
                  case "FIREBALL": //PAF
                      range = 150;
                          SpellInfo siFireBall = Root.I.SpellSystem.GetInfo("SPELL_FIREBALL");
                      successfulAttack = AttackWithSpell(Attacker, AttackedParty, pParam, range, siFireBall, pParam.neededMana, ref pParam.experienceGained);
                      pChar.Inventory.GetAttackingWeapon().L.DecrementChargesRemaining();
                      break;
                  case "SPIT": //PAF
                      range = 250;
                      //rnD5 = RNFireball;
                        SpellInfo siFireBallStrong = Root.I.SpellSystem.GetInfo("SPELL_FIREBALL");
                        successfulAttack = AttackWithSpell(Attacker, AttackedParty, pParam, range, siFireBallStrong, pParam.neededMana, ref pParam.experienceGained);
                        pChar.Inventory.GetAttackingWeapon().L.DecrementChargesRemaining();
                      break;

                  case "BASH": //PAF
                  case "HACK": //PAF
                  case "BERZERK": //PAF
                  case "KICK": //PAF
                  case "SWING": //PAF
                  case "CHOP": //PAF
                    //if (TimerTraceActive)
                    //{
                    //  fprintf(GETFILE(TraceFile), "Attack BASH/HACK/BERZERK/KICK/SWING/CHOP\n");
                    //}


                    // NOTE!  Fallthrough.
                  case "DISRUPT":
                  case "JAB":
                  case "PARRY":
                  case "STAB2":
                  case "STAB1":
                  case "STUN":
                  case "THRUST":
                  case "MELEE":
                  case "SLASH":
                  case "CLEAVE":
                  case "PUNCH":

                          //door
                          if ((pParam.attackType.Method == "BASH")||
                                (pParam.attackType.Method == "HACK") ||
                                (pParam.attackType.Method == "BERZERK") ||
                                (pParam.attackType.Method == "KICK") ||
                                (pParam.attackType.Method == "SWING") ||
                                (pParam.attackType.Method == "CHOP"))

                              HitDoor(Attacker, pParam);


                      successfulAttack = AttackWithPhysicalForce(Attacker, AttackedParty,pParam);
                      if (successfulAttack == 0)
                      {
                        pParam.experienceGained /= 2;
                        pParam.disableTime /= 2;
                      }
                      break;
                  case "CONFUSE":
                  case  "WARCRY":
                  case  "CALM":
                  case  "BRANDISH":
                  case  "BLOWHORN":
                          if (pParam.attackType.Method == "CONFUSE")
                              pChar.L.DecrementChargesRemaining();

                    successfulAttack = WarCryEtc(Attacker, pParam,pParam.attackX, pParam.attackY);
                    break;

                  case "SHOOT":
                      pParam.dataType = ATTACKDATATYPE.ADT_Shoot;
                      pParam.attdep.shoot.success = 0;
                      //if (    (pChar->Possession(0) == RNnul)
                      //     || (pChar->Possession(0).dbType() != dbWEAPON) )
                      //{
                      //  attackDamageToDisplay = -2;// Need Ammo(unsigned)0xfffe;
                      //  pParam.experienceGained = 0;
                      //  successfulAttack = 0;
                      //  //CallAttackFilter(&filter, pParam, 1);
                      //  break;
                      //}


                      //I guess the following is safe.  We could not have
                      //selected 'SHOOT' if we did not have the proper
                      //weapon in the weapon hand.
                      //DB5A2 = dbA2->CastToDB5(); //We will crash if not weapon
                      ItemData pWeapon_22 = Attacker.Inventory.GetAttackingWeapon();// TAG0099d2(pChar->Possession(0));
                      ItemData pWeapon_18 = Attacker.Inventory.GetAmmo();//&d.weapons[DB5A2->weaponType()];
                      D4W = 0;//pWeapon_18->uByte1;
                      //wpnByte1_4 = pWeapon_22->uByte1;
                      //if ( (D4W >= 16) && (D4W <= 31) ) //amoo type shooter
                      //{
                      //  if (wpnByte1_4 != 10)
                      //  {
                      //    attackDamageToDisplay = -2;//Need Ammo (unsigned)0xfffe;
                      //    pParam.experienceGained = 0;
                      //    successfulAttack = 0;
                      //    //CallAttackFilter(&filter, pParam, 1);
                      //    break;
                      //  };
                      //  D4W -= 16;
                      //}
                      //else
                      //{
                      //  if ( (D4W >= 32) && (D4W <= 47) ) // ammo shooter
                      //  {
                      //      if (wpnByte1_4 != 11)
                      //      {
                      //          attackDamageToDisplay = -2; //Need Ammo  (unsigned)0xfffe;
                      //          pParam.experienceGained = 0;
                      //          successfulAttack = 0;
                      //          //CallAttackFilter(&filter, pParam, 1);
                      //          break;
                      //      }
                            
                      //      D4W -= 32;
                      //  }
                      //}
                          pChar.L.SetCharToPartyFacing(AttackedParty);
                          ItemData weapon = pChar.Inventory.GetAttackingWeapon();
                          ItemData id = pChar.L.RemoveCharacterPossession(weapon);

                          //projectile
                      //obj_4 = RemoveCharacterPossession(pParam->charIdx, 0);
                      //QueueSound(16, d.partyX, d.partyY, 1);
                      w_42 = (DetermineMastery(Attacker,pParam.charIdx, 11));
                      pParam.attdep.shoot.range = pWeapon_18.Distance + pWeapon_22.Distance;
                      pParam.attdep.shoot.damage = 2 * (pWeapon_18.Damage + w_42);
                      pParam.attdep.shoot.damage = D4W;
                      pParam.attdep.shoot.success = 1;
                      //CallAttackFilter(&filter, pParam, 1);
                      LaunchObject(
                                   pChar,
                                   id,
                                   pParam.attdep.shoot.range,
                                   pParam.attdep.shoot.damage,
                                   pParam.attdep.shoot.damage );
                      break;
                  case "FLIP": 
                      pParam.attdep.flip.heads = STRandomBool();
                      //CallAttackFilter(&filter, pParam, 1);
                      if (pParam.attdep.flip.heads != 0)
                      {
                        //PrintWithSubstitution("IT COMES UP HEADS", 4, true);
                      }
                      else
                      {
                        //PrintWithSubstitution("IT COMES UP TAILS", 4, true);
                      };
                      break;
                  case "SPELLSHIELD"://PAF
                  case "FIRESHIELD"://PAF
                      pParam.attdep.shield.mustHaveMana = 1;
                      pParam.attdep.shield.strength = 0x118;
                      pParam.dataType = ATTACKDATATYPE.ADT_Shield;
                      //CallAttackFilter(&filter, pParam, 1);
                      D0W = MagicShield(pChar,
                                       pParam.attackType.Method=="SPELLSHIELD" ? 1 : 0,
                                       pParam.attdep.shield.strength,
                                       pParam.attdep.shield.mustHaveMana);
                      if (D0W == 0)
                      {
                        pParam.experienceGained /= 4;
                        pParam.disableTime /= 2;
                      }
                      else
                      {
                          pChar.Inventory.GetAttackingWeapon().L.DecrementChargesRemaining();
                      };
                      break;
                      case "INVOKE":
                      range = STRandom(128) + 100;
                          SpellInfo six = null;
                          //;Root.I.SpellSystem.GetInfo("SPELL_FIREBALL");                          
                      switch (STRandom(6))
                      {
                      case 0: six = Root.I.SpellSystem.GetInfo("SPELL_POISON_BOLT"); break;
                      case 1: six = Root.I.SpellSystem.GetInfo("SPELL_POISON_CLOUD"); break;
                      case 2: six = Root.I.SpellSystem.GetInfo("SPELL_DISPELL_MISILLE"); break;
                      default: six = Root.I.SpellSystem.GetInfo("SPELL_FIREBALL"); break;
                      };
                      successfulAttack = AttackWithSpell(Attacker, AttackedParty, pParam, range, six, pParam.neededMana, ref pParam.experienceGained);
                      break;
                  case "FLUXCAGE": //PAF
                    pChar.L.SetCharToPartyFacing(AttackedParty);
                    //FluxCage(pParam->attackX, pParam->attackY, pParam);
                    pParam.dataType = ATTACKDATATYPE.ADT_FluxCage;
                    //CallAttackFilter(&filter, pParam, 1);
                    break;
                  case "FUSE":
                    pChar.L.SetCharToPartyFacing(AttackedParty);
                    //w_6 = d.partyX;
                    //w_8 = d.partyY;
                    //pParam.attackX = d.partyX + d.DeltaX[d.partyFacing];
                    //pParam.attackY = d.partyY + d.DeltaY[d.partyFacing];
                    //pParam->dataType = ADT_Fusion;
                    //CallAttackFilter(&filter, pParam, 1);
                    //Fusion(_8_,pParam->attackX, pParam->attackY);
                    break;
                  case "HEAL": //PAF
                    neededHP_4 = pChar.Attributes.Health.Max - pChar.Attributes.Health.Current;
                    pParam.dataType = ATTACKDATATYPE.ADT_Heal;
                    if (neededHP_4 > 0)
                    {
                        if (pChar.Attributes.Mana.Current != 0)
                      {
                        successfulAttack = 1;
                        //D4W = sw(Smaller(10, DetermineMastery(pParam->charIdx, 13)));
                        pParam.attdep.heal.HPIncrement 
                                = (Smaller(10, DetermineMastery(Attacker,pParam.charIdx, 13)));
                        pParam.experienceGained = 2;
                        //CallAttackFilter(&filter, pParam, 1);
                        do
                        {
                          //D6W = sw(Smaller(neededHP_4, D4W));
                          D6W = (Smaller(neededHP_4, pParam.attdep.heal.HPIncrement));
                          pChar.Attributes.Health.Incr(D6W);
                          pParam.experienceGained += 2;
                          pChar.Attributes.Mana.Incr(-2);
                          if (pChar.Attributes.Mana.Current < 0) break;
                            neededHP_4 -= D6W;
                        } while (neededHP_4 != 0);
                        if (pChar.Attributes.Mana.Current < 0) pChar.Attributes.Mana.SetCurrent(0);
                        pChar.CharFlags |= CHARFLAGS.CHARFLAG_statsChanged; //0x100;
                      };
                    }
                    else
                    {
                      successfulAttack = 0;
                      //D4W = sw(Smaller(10, DetermineMastery(pParam->charIdx, 13)));
                      pParam.attdep.heal.HPIncrement = 0;
                      //CallAttackFilter(&filter, pParam, 1);
                    };
                    break;
                  case "WINDOW": //PAF
                    D4W = (STRandom(DetermineMastery(Attacker, pParam.charIdx, pParam.skillNumber) + 8) + 5);
//                    timer_32.timerUByte5(0);
  //                  timer_32.Function(TT_73);
    //                timer_32.timerTime = ((d.partyLevel << 24) | d.Time) + D4W;
      //              gameTimers.SetTimer(&timer_32);
                    Root.I.GameSystem.SeeThruWalls++;
                    pParam.dataType = ATTACKDATATYPE.ADT_Window;
                    //CallAttackFilter(&filter, pParam, 1);
                    pChar.Inventory.GetAttackingWeapon().L.DecrementChargesRemaining();
                    break;
                  case "CLIMBDOWN"://PAF
                          TileData td = Attacker.L.GetRoomInFrontOfMe(1);
                          PartyData pd = td.L.ContainsParty();
                    //pParam->attackX = d.partyX;
                    //pParam->attackY = d.partyY;
                    //pParam->attackX += d.DeltaX[d.partyFacing];
                    //pParam->attackY += d.DeltaY[d.partyFacing];
                    //rtD0 = RoomType(GetCellFlags(pParam->attackX, pParam->attackY));

                    if (   (td.TileType == TileType.Pit) && (pd == null) )
                    {
                      Root.I.GameSystem.SupressPitDamage = 1;
                        
                        AttackersParty.MoveParty(new DungeonLoc());
                      //Root.I.GameSystem.MoveObject(RN(RNnul), AttackersParty.Location.X, AttackersParty.Location.Y, pParam.attackX, pParam.attackY, null, null);
                      Root.I.GameSystem.SupressPitDamage = 0;
                    }
                    else
                    {
                      pParam.disableTime = 0;
                    };
                    pParam.dataType = ATTACKDATATYPE.ADT_ClimbDown;
                    //CallAttackFilter(&filter, pParam, 1);
                    break;
                  case "FREEZELIFE":
                    D4W = 0;
                    ItemData idMagicBox = Attacker.Inventory.GetAttackingWeapon();
                          if (idMagicBox.InfoId == "ITEM_MAGICAL_BOX_A") D4W = 30;
                          if (idMagicBox.InfoId == "ITEM_MAGICAL_BOX_B") D4W = 125;

                    if (D4W != 0)
                    {
                        ItemData iddd = Attacker.Inventory.GetAttackingWeapon();
                        Attacker.L.RemoveCharacterPossession(iddd);
                      //RemoveCharacterPossession(pParam->charIdx, 1);
                      //DB10A2->link(RNnul);//The box is gone.
                        Root.I.ItemSystem.RemoveData(iddd);
                      //DeleteDBEntry(DB10A2);
                    }
                    else
                    {
                      D4W = 70;
                      pChar.L.DecrementChargesRemaining();
                    };
                    pParam.dataType = ATTACKDATATYPE.ADT_FreezeLife;
                    pParam.attdep.freezeLife.oldTime = Root.I.GameSystem.FreezeLifeTimer;
                    if (Root.I.GameSystem.FreezeLifeTimer + D4W > 200) D4L = 200 - Root.I.GameSystem.FreezeLifeTimer;
                    if (D4W < 0) D4W = 0;
                    pParam.attdep.freezeLife.deltaTime = D4W;
                    //CallAttackFilter(&filter, pParam, 1);
                    Root.I.GameSystem.FreezeLifeTimer = (Smaller(255, Root.I.GameSystem.FreezeLifeTimer + pParam.attdep.freezeLife.deltaTime));
                    break;
                  case "LIGHT":
                    pParam.dataType = ATTACKDATATYPE.ADT_Light;
                    pParam.attdep.light.deltaLight = 213;//d.Word1074[2];
                    pParam.attdep.light.time       = 2500;
                    pParam.attdep.light.decayRate  = -2;
                    //d.Brightness = sw(d.Brightness + d.Word1074[2]);
                    //SetBrightnessTimer(-2, 2500);
                    //CallAttackFilter(&filter, pParam, 1);
                    Root.I.GameSystem.Brightness = (Root.I.GameSystem.Brightness + pParam.attdep.light.deltaLight);
                    //SetBrightnessTimer(
                    //        pParam->attdep.light.decayRate, 
                    //        pParam->attdep.light.time);
                    pChar.Inventory.GetAttackingWeapon().L.DecrementChargesRemaining();
                         // pChar.L.DecrementChargesRemaining();
                    //DecrementChargesRemaining(pChar);
                    break;
                  case "THROW": //PAF
                          pChar.L.SetCharToPartyFacing(AttackedParty);
                      //if (   (pChar->charPosition == ((d.partyFacing + 1)&3))
                      //    || (pChar->charPosition == ((d.partyFacing + 2)&3)) )
                      //{
                      //  D0W = 1; //right side
                      //}
                      //else
                      //{
                      //  D0W = 0; //left side
                      //};

                          //toto je mnou dodane
                          D0W = 0;

                          

                      pParam.dataType = ATTACKDATATYPE.ADT_Throw;
                      pParam.disableTime = -1;
                      pParam.attdep.thro.side = D0W;
                      pParam.attdep.thro.abort = 0;
                      pParam.attdep.thro.facing = Attacker.Facing;
                      pParam.attdep.thro.range = -1;
                      pParam.attdep.thro.damage = -1;
                      pParam.attdep.thro.decayRate = -1;
                      //CallAttackFilter(&filter, pParam, 1);
                      if (pParam.attdep.thro.abort == 0)
                      {
                        successfulAttack = ThrowByCharacter(pChar, pParam.charIdx, 1, D0W, pParam.disableTime,
                                                            pParam.attdep.thro.range,
                                                            pParam.attdep.thro.damage,
                                                            pParam.attdep.thro.decayRate
                                                            );
                        // If successful the character's disable timer is set.
                      }
                      else
                      {
                        successfulAttack = 0;
                      };



                      //D5W = ThrowByCharacter(chIdx, 1, D0W);
                      //if (D5W != 0)
                      //{
                        //ASSERT(pChar->busyTimer != -1);
                        //d.pTimer(pChar->busyTimer)->timerUByte6 = 2;
                      //};
                 


                      if (successfulAttack != 0)
                      {
                        //ASSERT(pChar->busyTimer != -1,"busyTimer == -1");
                        //
                        // Set disable time to zero.  We have already sent a timer
                        // a few lines up in 'ThrowByCharacter'.  If disable time
                        // is non-zero we will do another 'DisableCharacterAction' just
                        // after this 'switch' construct and that will cause the 'timerUByte6'
                        // to be cleared.  That in turn will cause the champion's hand
                        // not to be refilled when the timer expires.
                        //if (pParam->disableTime > 255) pParam->disableTime = 255;
                        //gameTimers.pTimer(pChar->busyTimer)->timerUByte6((ui8)((pParam->disableTime<0)?2:pParam->disableTime));
                        pParam.disableTime = 0;
                      };
                      break;
                  default:
                    pParam.dataType = ATTACKDATATYPE.ADT_Default;
                    //CallAttackFilter(&filter, pParam, 1);
                    break;
                  } //switch ()
                  //CallAttackFilter(&filter, pParam, 2);
                  if (pParam.disableTime != 0)
                  {
                      Root.I.GameSystem.DisableCharacterAction(pChar, pParam.disableTime);
                  }
                  if (pParam.staminaCost != 0)
                  {
                      //pChar.Stamina.Add(pParam.staminaCost);
                    AdjustStamina(pChar, pParam.staminaCost);
                  }
                  if (pParam.experienceGained != 0)
                  {
                    AdjustSkills(pChar, pParam.charIdx, pParam.skillNumber, pParam.experienceGained, ADJUSTSKILLSWHY.ASW_Attack);
                  };
                  //if (TimerTraceActive)
                  //{
                  //  fprintf(GETFILE(TraceFile), " Increase skill %02x by %02x to %02x\n", 
                  //          pParam->skillNumber,
                  //          pParam->experienceGained,
                  //          pChar->skills92[pParam->skillNumber].experience);
                  //};
                  //DrawCharacterState(pParam->charIdx);
                  //if (pParam.activateMonster != 0)
                  //{
                  //  //This used to be done in the 'DeterminePhysicalAttackDamage' code.  But
                  //  //activating the monster caused the MonsterMoveFilter to be
                  //  //called and that destroyed the DSA parameter area.  We could have
                  //  //saved the parameters and restored them but even then it 
                  //  //would cause the filters to be kind of 'nested'.  The 
                  //  //Party Attack Filter would still be active when the Monster Movement
                  //  //Filter was called.  I doubt it would be a problem but I'd rather
                  //  //not find out that I was wrong.  So we delay the monster activation
                  //  //until we are all done with the Party Attack Filter.
                  //  //ProcessTimers29to41(pParam->attackX, 
                  //  //                    pParam->attackY, 
                  //  //                    TT_M1, 
                  //  //                    0);
                  //};

            //return successfulAttack;
                 // RETURN_int(successfulAttack);
                }

        //*********************************************************
        //
        //*********************************************************
        //  TAG017570
        public int ThrowByCharacter(CreatureData pChar, int chIdx, int hand, int LeftOrRight, int disableTime,
                             int range, int damage, int decayRate)
            {//(i16)
            //  int D5L, D5W, D6L, D6W, D7L, D7W;
            //  WEAPONDESC *weaponDescA2;
            //  CreatureData   pcA3;
            //  ItemData objD4;
            //  //i16 w_4;
            //  RN  origObjInWeaponHand = RNnul;
            ////;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
            //  //w_4 = 0;
            //  if (hand < 0)
            //  {
            //      if (Root.I.GameSystem.ItemInHand==null) return 0;


            //    {
            //      CURSORFILTER_PACKET cfp;
            //      cfp.type = CURSORFILTER_TYPE.CURSORFILTER_Throw;
            //      cfp.bo = Root.I.GameSystem.ItemInHand;// d.objectInHand.ConvertToInteger();
            //      cfp.p1 = LeftOrRight;
            //      //CursorFilter(&cfp);

            //      if (cfp.type == CURSORFILTER_TYPE.CURSORFILTER_Cancel) return 0;

            //      objD4 = pChar.L.RemoveObjectFromItemInHand();
            //    }

            //    pcA3 = pChar;
            //    origObjInWeaponHand = pcA3->Possession(1); // Save contents of fighting hand
            //    pcA3->SetPossession(1, objD4,false); //put obect into fighting hand.
            //    hand = 1;
            //    if (record)
            //    {
            //      RecordFile_Record(x, y, f);
            //    };
            //    D7W = (i16)DetermineThrowingDistance(chIdx, hand);
            //    pcA3->SetPossession(hand, origObjInWeaponHand, false);  // Replace object in weapon hand.
            //  }
            //  else
            //  {
            //    if (d.CH16482[chIdx].Possession(hand) != RNnul)
            //    {
            //      if (record)
            //      {
            //        RecordFile_Record(x, y, f);
            //      };
            //    };
            //    D7W = (i16)DetermineThrowingDistance(chIdx, hand);
            //    objD4 = RemoveCharacterPossession(chIdx, hand);
            //    if (objD4 == RNnul) return 0;
            //  };
            //  QueueSound(16, d.partyX, d.partyY, 1);
            //  AdjustStamina(chIdx, TAG016382(objD4));
            //  DisableCharacterAction(chIdx, (disableTime<0)?4:disableTime);
            //  D6W = 8;
            //  D5W = 1;
            //  //D0W = ;
            //  if (objD4.dbType() == dbWEAPON)
            //  {
            //    D6W += 4;
            //    weaponDescA2 = TAG0099d2(objD4);
            //    if (weaponDescA2->uByte1 <= 12)
            //    {
            //      D5W = weaponDescA2->uByte3;
            //      D6W = sw(D6W + D5W/4);
            //    };
            //  };
            //  AdjustSkills(chIdx, 10, D6W, ASW_ThrowByCharacter);
            //  D7W = sw(D7W + D5W);
            //  D5W = (i16)DetermineMastery(chIdx, 10); // Skill #10
            //  D7W = sw(D7W + STRandom(16) + D7W/2 + D5W);
            //  D6W = ApplyLimits(40, 8*D5W + (STRandom()&31), 200);
            //  D5W = sw(Larger(5, 11 - D5W));
            //  LaunchMissile(
            //                objD4,
            //                d.partyX,
            //                d.partyY,
            //                (d.partyFacing+LeftOrRight)&3,
            //                d.partyFacing,
            //                (range<0)?D7W:range,  //range
            //                (damage<0)?D6W:damage,  //damage
            //                (decayRate<0)?D5W:decayRate,  //DecayRate
            //                false);
            //  d.Word11712 = 4;
            //  d.Word11714 = d.partyFacing;
            //  DrawCharacterState(chIdx);
              return (1);
            }



        public void HitDoor(CreatureData Attacker, ATTACKPARAMETERS pParam)
        {
            TileData td = Attacker.L.GetRoomInFrontOfMe(1);
            if (td == null) return;
            

            if (td.TileType == TileType.Door) //
            {
                if (td.IsBreakable) // Is it a breakable door?
                {
                    //QueueSound(16, d.partyX, d.partyY, 1);
                    pParam.dataType = ATTACKDATATYPE.ADT_HitDoor;
                    pParam.disableTime = 6;
                    pParam.attdep.hitDoor.strength = DetermineThrowingDistance(Attacker, pParam.charIdx, 1);
                    //CallAttackFilter(&filter, pParam, 1);
                    //HitDoor(pParam->attackX,
                    //        pParam->attackY,
                    //        pParam->attdep.hitDoor.strength,
                    //        0,  //Not a ZO spell
                    //        2); //delay
                    //QueueSound(4, d.partyX, d.partyY, 2);
                    //break only for door
                }
            }
        }


        //*********************************************************
        //
        //*********************************************************
        //  TAG01bd5e
        public int MagicShield(CreatureData pChar, int spellShield, int strength, int mustHaveMana)
        {
            int D6L, D6W;
            //TIMER timer;
            //;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
            //D7W = sw(P3);
            D6W = 1;
            if (mustHaveMana != 0)
            {
                if (pChar.Attributes.Mana.Current == 0) return 0;
                if (pChar.Attributes.Mana.Current < 4)
                {
                    strength /= 2;
                    pChar.Attributes.Mana.SetCurrent(0);
                    D6W = 0;
                }
                else
                {
                    pChar.Attributes.Mana.Incr(-4);
                };
            };
            //timer.timerWord6() = sw(strength / 32);
            //if (spellShield != 0)
            //{
            //    timer.Function(TT_77);
            //    if (d.SpellShield > 50)
            //    {
            //        timer.timerWord6() /= 4;
            //    };
            //    d.SpellShield = sw(d.SpellShield + timer.timerWord6());
            //}
            //else
            //{
            //    timer.Function(TT_78);
            //    if (d.FireShield > 50)
            //    {
            //        timer.timerWord6() /= 4;
            //    };
            //    d.FireShield = sw(d.FireShield + timer.timerWord6());
            //};
            //timer.timerUByte5(0);
            //timer.timerTime = (d.Time + (UI16)(strength)) | (d.partyLevel << 24);
            ////timer.uByte6 = (ui8)timer.word6(); // Value expected in first byte
            //// Not So!!!  We use the whole word.
            //gameTimers.SetTimer(&timer);
            //MarkAllPortraitsChanged();
            return D6W;
        }






    }
}
